﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Web;
using System.Web.Helpers;
using System.Web.WebPages;
using System.Web.WebPages.Scope;

public static class Polldaddy
{
    private const string ApiUrl = "https://api.polldaddy.com/";

    private const string SurveyOEmbedUrl = "http://polldaddy.com/oembed?url=http%3A//surveys.polldaddy.com/s/{0}/&format=json&link_text={1}";
    private const string PollOEmbedUrl = "http://polldaddy.com/oembed?url=http%3A//answers.polldaddy.com/poll/{0}/&format=json";
    private const string RatingOEmbedUrl = "http://polldaddy.com/oembed?url=http%3A//polldaddy.com/ratings/{0}/&format=json&title{1}&permalink={2}";

    private const string InitializedExceptionMessage = "The Polldaddy Helper has not been initialized.";
    private const string ArgumentNullExceptionMessage = "Argument cannot be null or empty.";
    private const string ApiErrorMessage = "Polldaddy API error: {0}";

    private static readonly object _apiKey = new object();
    private static readonly object _userCodeKey = new object();
    private static readonly object _initializedKey = new object();
    
    public static string ApiKey {
        get {
            if (!Initialized) {
                throw new InvalidOperationException(InitializedExceptionMessage);
            }

            return (string)(ScopeStorage.CurrentScope[_apiKey] ?? "");
        }

        private set {
            if (value == null) {
                throw new ArgumentNullException("ApiKey");
            }

            ScopeStorage.CurrentScope[_apiKey] = value;
        }
    }

    public static string UserCode {
        get {
            if (ScopeStorage.CurrentScope[_userCodeKey] == null) {
                ScopeStorage.CurrentScope[_userCodeKey] = GetUserCode();
            }

            return (string)ScopeStorage.CurrentScope[_userCodeKey];
        }
    }

    private static bool Initialized {
        get {
            return (bool)(ScopeStorage.CurrentScope[_initializedKey] ?? false);
        }

        set {
            ScopeStorage.CurrentScope[_initializedKey] = value;
        }
    }

    /// <summary>
    /// Initializes the Polldaddy helper.
    /// </summary>
    /// <param name="apiKey">The API key assigned to your account.</param>
    public static void Initialize(string apiKey) {
        if (apiKey.IsEmpty())
        {
            throw new ArgumentException(ArgumentNullExceptionMessage, "apiKey");
        }

        ApiKey = apiKey;

        Initialized = true;
    }

    /// <summary>
    /// Retrieves the PollDaddy API Usercode.
    /// </summary>
    public static string GetUserCode() {
        dynamic request = new {
            pdAccess = new {
                partnerGUID = ApiKey,
                partnerUserID = "0", 
                demands = new {
                    demand = new {
                        id = "GetUserCode"
                    }
                }
            }
        };

        var client = new WebClient();
        client.Headers.Add("content-type", "application/json");
        var jsonRequest = Json.Encode(request);
        var jsonResponse = client.UploadString(ApiUrl, jsonRequest);
        var response = Json.Decode(jsonResponse);

        return response.pdResponse.userCode;
    }

    /// <summary>
    /// Retrieves the results of the given poll.
    /// </summary>
    /// <param name="pollId">The poll Id.</param>
    public static IList<dynamic> GetPollResults(string pollId) {
        dynamic request = new {
            pdRequest = new {
                partnerGUID = ApiKey,
                userCode = UserCode,
                demands = new {
                    demand = new {
                        poll = new {
                            id = pollId
                        },
                        id = "GetPollResults"
                    }
                }
            }
        };

        var client = new WebClient();
        client.Headers.Add("content-type", "application/json");
        var jsonResponse = client.UploadString(ApiUrl, Json.Encode(request));
        var response = Json.Decode(jsonResponse);

        if (response.pdResponse.errors != null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ApiErrorMessage, response.pdResponse.errors.error[0].content));
        }

        var results = response.pdResponse.demands.demand[0].result.answers.answer;
        
        return new List<dynamic>(results ?? new dynamic[] {});
    }
    
    /// <summary>
    /// Retrieves the details of the given poll.
    /// </summary>
    /// <param name="pollId">The poll id.</param>
    /// <returns></returns>
    public static dynamic GetPoll(string pollId) {
        dynamic request = new {
            pdRequest = new {
                partnerGUID = ApiKey,
                userCode = UserCode,
                demands = new {
                    demand = new {
                        poll = new {
                            id = pollId
                        },
                        id = "GetPoll"
                    }
                }
            }
        };

        var client = new WebClient();
        client.Headers.Add("content-type", "application/json");
        var jsonResponse = client.UploadString(ApiUrl, Json.Encode(request));
        var response = Json.Decode(jsonResponse);

        if (response.pdResponse.errors != null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ApiErrorMessage, response.pdResponse.errors.error[0].content));
        }

        return response.pdResponse.demands.demand[0].poll;
    }

    /// <summary>
    /// Gets the list of poll comments
    /// </summary>
    /// <param name="pollId">The Id of the poll</param>
    /// <returns>A list of comments</returns>
    public static IList<dynamic> GetPollComments(string pollId)
    {
        dynamic request = new
        {
            pdRequest = new
            {
                partnerGUID = ApiKey,
                userCode = UserCode,
                demands = new
                {
                    demand = new
                    {
                        poll = new
                        {
                            id = pollId
                        },
                        id = "GetPollComments"
                    }
                }
            }
        };

        var client = new WebClient();
        client.Headers.Add("content-type", "application/json");
        var jsonResponse = client.UploadString(ApiUrl, Json.Encode(request));
        var response = Json.Decode(jsonResponse);

        if (response.pdResponse.errors != null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ApiErrorMessage, response.pdResponse.errors.error[0].content));
        }

        var comments = response.pdResponse.demands.demand[0].comments.comment;
        
        return new List<dynamic>(comments ?? new dynamic[] {});
    }

    /// <summary>
    /// Shows a link to open the survey as a website popup.
    /// </summary>
    /// <param name="surveyId">The Id of the survey.</param>
    /// <param name="linkText">The text to display in the survey opening link.</param>    
    public static HtmlString GetSurveyLink(string surveyId, string linkText = "Take Our Survey!") {
        var url = String.Format(CultureInfo.InvariantCulture, SurveyOEmbedUrl, surveyId, HttpUtility.UrlEncode(linkText));

        var client = new WebClient();
        var result = client.DownloadString(url);
        var embedResponse = Json.Decode(result);

        return new HtmlString(embedResponse.Html);
    }

    /// <summary>
    /// Shows the poll widget.
    /// </summary>
    /// <param name="pollId">The Id of the poll.</param>
    public static HtmlString GetPollWidget(string pollId) {
        var url = String.Format(CultureInfo.InvariantCulture, PollOEmbedUrl, pollId);

        var client = new WebClient();
        var result = client.DownloadString(url);
        var embedResponse = Json.Decode(result);

        return new HtmlString(embedResponse.Html);
    }

    /// <summary>
    /// Shows the rating widget.
    /// </summary>
    /// <param name="ratingId">The Id of the rating.</param>
    public static HtmlString GetRatingWidget(string ratingId, string title = "", string permalink = "") {
        var url = String.Format(CultureInfo.InvariantCulture, RatingOEmbedUrl, ratingId, HttpUtility.UrlEncode(title), HttpUtility.UrlEncode(permalink));

        var client = new WebClient();
        var result = client.DownloadString(url);
        var embedResponse = Json.Decode(result);

        return new HtmlString(embedResponse.Html);
    }
}
